package com.ruoyi.quartz.service.impl;

import com.ruoyi.bus.domain.*;
import com.ruoyi.bus.service.*;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.quartz.service.IPlanBusCService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class PlanBusCServiceImpl implements IPlanBusCService {


    @Autowired
    private IWitAppointService appointService;
    @Autowired
    private IWitRouteService routeService;
    @Autowired
    private IWitBusService busService;
    @Autowired
    private IWitPlanService planService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private IWitChangeDriverService changeDriverService;

    private static String seatReservation;

    @Transactional
    public void changePlanUser(String driveTimes, Date date){
        WitChangeDriver changeDriver = new WitChangeDriver();
        changeDriver.setDriveTime(driveTimes);
        changeDriver.setGotoTime(date);
        List<WitChangeDriver> changeDriverList = changeDriverService.selectWitChangeDriverList(changeDriver);
        if(changeDriverList.size() == 0){
            log.info("today is not change driver user, do not changePlanUser");
            return;
        }
        for(WitChangeDriver witChangeDriver : changeDriverList){
            String driveTime = witChangeDriver.getDriveTime();
            Date gotoTime = witChangeDriver.getGotoTime();
            WitPlan witPlan = new WitPlan();
            witPlan.setSendTime(gotoTime);
            witPlan.setDriveTime(driveTime);
            witPlan.setRouteId(witChangeDriver.getRouteId());
            List<WitPlan> witPlanList = planService.selectWitPlanList(witPlan);
            if(witPlanList.size() == 0){//没排班，说明这个人今天不用出车
                witChangeDriver.setChangeStatus(2);
                witChangeDriver.setRemark("没有预约用户，该司机无需出车.");
                changeDriverService.updateWitChangeDriver(witChangeDriver);
                continue;
            }
            witPlan = witPlanList.get(0);
            SysUser sysUser = userService.selectUserById(witChangeDriver.getNewUserId());
            WitPlan planTemp = new WitPlan();
            planTemp.setDriverUserId(sysUser.getUserId());
            planTemp.setSendTime(gotoTime);
            planTemp.setDriveTime(driveTime);
            List<WitPlan> witPlans = planService.selectWitPlanList(planTemp);
            if(witPlans.size() != 0){
                witChangeDriver.setChangeStatus(4);
                witChangeDriver.setRemark("新司机已被排班,无法换班");
                changeDriverService.updateWitChangeDriver(witChangeDriver);
                continue;
            }
            if(witChangeDriver.getChangeBus().intValue() == 1){//1为更改车辆信息
                WitBus witBus = new WitBus();
                witBus.setUserId(sysUser.getUserId());
                witBus.setBusStatus(0);
                List<WitBus> witBusList = busService.selectWitBusList(witBus);
                if(witBusList.size() == 0){
                    witChangeDriver.setChangeStatus(3);
                    witChangeDriver.setRemark("新司机不存在绑定车辆");
                    changeDriverService.updateWitChangeDriver(witChangeDriver);
                    continue;
                }
                witBus = witBusList.get(0);
                witPlan.setBusId(witBus.getBusId());
                witPlan.setBusModel(witBus.getBusModel());
                witPlan.setBusNumber(witBus.getBusNumber());
            }
            witPlan.setDriverUserId(sysUser.getUserId());
            witPlan.setDriverUserName(sysUser.getUserName());
            planService.updateWitPlan(witPlan);
            witChangeDriver.setUserId(1l);
            witChangeDriver.setUserName("系统管理员");
            witChangeDriver.setRemark("系统自动换班");
            witChangeDriver.setPlanId(witPlan.getPlanId());

            WitAppoint witAppoint = new WitAppoint();
            witAppoint.setDriverUserId(sysUser.getUserId());
            witAppoint.setDriverUserName(sysUser.getUserName());
            witAppoint.setDriverUserPhone(sysUser.getPhonenumber());
            witAppoint.setPlanId(witPlan.getPlanId());

            if(witChangeDriver.getChangeBus().intValue() == 1){//给与预约数据更改
                witAppoint.setBusModel(witPlan.getBusModel());
                witAppoint.setBusId(witPlan.getBusId());
                witAppoint.setBusNumber(witPlan.getBusNumber());
            }

            appointService.updateWitAppointByPlanId(witAppoint);

            changeDriverService.updateWitChangeDriver(witChangeDriver);
        }
    }

    @Override
    @Transactional
    public void plan(String driveTimes, Date date) {
        try{
            List<WitAppoint> witAppointList = this.listAppointData(driveTimes, date);
            if(witAppointList.size() == 0){
                log.info("today is not appoint, do not plan");
                return;
            }
            for(WitAppoint witAppoint : witAppointList){
                List<WitRoute> witRouteList = this.listRouteByUserAppoint(witAppoint);
                if(witRouteList.size() == 0){
                    log.info("no route used, the appointId is : " + witAppoint.getAppointId());
                    this.updateAppointStatusToNoBus(witAppoint);//状态更新为无车辆使用,没有找到路线
                    continue;
                }
                this.handlePlan(witRouteList, witAppoint);
            }
        }catch(Exception e){
            log.error("排班"+ driveTimes +"计划执行失败,异常为:" + e);
            throw e;
        }

    }


    private List<WitAppoint> listAppointData(String driveTime, Date date){
        WitAppoint appoint = new WitAppoint();
        appoint.setAppointStatus(0);//已预约
        appoint.setTempStatus(0);//临时预约不参与排班
        appoint.setGotoTime(date);
        appoint.setDriveTime(driveTime);
        appoint.setIsPlan(2);//未排班过得用户
        return appointService.selectWitAppointList(appoint);
    }

    private void handlePlan(List<WitRoute> witRoutes, WitAppoint witAppoint){
        Long userAppointRouteId = witAppoint.getRouteId();
        boolean flag = false;
        for(WitRoute route : witRoutes){
            if(route.getRouteId().longValue() == userAppointRouteId.longValue()){//是自己预约的路线
                flag = this.handlePlan(route, witAppoint);//返回true证明排班成功,返回false证明失败,可能是没有车或者满了等原因,需要安排其他车辆
                if(!flag){
                    witRoutes.remove(route);
                    break;
                }
            }
        }

        if(!flag){
            for(WitRoute route : witRoutes){
                if(this.handlePlan(route, witAppoint)){//返回true证明排班成功,返回false证明失败,可能是没有车或者满了等原因,需要安排其他车辆
                    break;
                }
            }
        }

        WitAppoint temp = appointService.selectWitAppointById(witAppoint.getAppointId());
        if(temp.getPlanId() == null){
            this.updateAppointStatusToNoBus(witAppoint);
        }
    }

    private boolean handlePlan(WitRoute route, WitAppoint witAppoint){
        String driveTimes = witAppoint.getDriveTime();
        Date date = witAppoint.getGotoTime();
        Long routeId = route.getRouteId();
        WitPlan witPlan = new WitPlan();
        witPlan.setSendTime(date);
        witPlan.setRouteId(routeId);
        witPlan.setDriveTime(driveTimes);
        witPlan.setPlanStatus(0);
        List<WitPlan> witPlanList = planService.selectWitPlanList(witPlan);
        if(witPlanList.size() == 0){//没有排班
            return this.createPlan(route, driveTimes, date, witAppoint.getAppointId());
        }else{//有排班
            return this.updatePlan(witPlanList.get(0), witAppoint.getAppointId());
        }
    }

    public boolean updatePlan(WitPlan witPlan, Long appointId){
        int seatReservation = this.getSeatReservation();//车座位预留数
        WitBus witBus = busService.selectWitBusById(witPlan.getBusId());
        if(witBus == null){//没有车可以使用
            return false;
        }
        Integer userCount = witPlan.getAppointCount();
        if(userCount >= witBus.getFullLoad() - seatReservation){
            return false;
        }
        witPlan.setAppointCount(witPlan.getAppointCount() + 1);
        planService.updateWitPlan(witPlan);
        this.updateAppointPlan(appointId, witBus, witPlan, getDriverUser(witBus.getUserId()).getPhonenumber());
        return true;
    }

    public boolean createPlan(WitRoute route, String driveTimes, Date date, Long appointId){
        WitPlan witPlan = new WitPlan();
        witPlan.setAppointCount(0);//预约数
        WitBus witBus = this.getBus(route.getRouteId(), witPlan);
        if(witBus == null){//没有车可以使用
            return false;
        }
        witPlan.setAppointCount(witPlan.getAppointCount() + 1);
        witPlan.setBusId(witBus.getBusId());
        witPlan.setBusModel(witBus.getBusModel());
        witPlan.setBusNumber(witBus.getBusNumber());
        witPlan.setDriverUserId(witBus.getUserId());
        SysUser user = getDriverUser(witBus.getUserId());
        witPlan.setDriverUserName(user.getUserName());
        witPlan.setDriveTime(driveTimes);
        witPlan.setRouteId(route.getRouteId());
        witPlan.setRouteName(route.getRouteName());
        witPlan.setTempAppointCount(0);
        if(driveTimes.equals("am")){
            witPlan.setSendTime(DateUtils.splicingTime(date, route.getStartAmTime()));//发车时间
        }else {
            witPlan.setSendTime(DateUtils.splicingTime(date, route.getStartPmTime()));//发车时间
        }
        planService.insertWitPlan(witPlan);
        this.updateAppointPlan(appointId, witBus, witPlan, user.getPhonenumber());
        return true;
    }

    private void updateAppointStatusToNoBus(WitAppoint witAppoint){
        witAppoint.setAppointStatus(4);
        appointService.updateWitAppoint(witAppoint);
    }

    private void updateAppointPlan(Long appointId, WitBus witBus, WitPlan witPlan, String driverUserPhone){
        WitAppoint witAppoint = new WitAppoint();
        witAppoint.setAppointId(appointId);
        witAppoint.setBusId(witBus.getBusId());
        witAppoint.setBusModel(witBus.getBusModel());
        witAppoint.setBusNumber(witBus.getBusNumber());
        witAppoint.setDriverUserId(witPlan.getDriverUserId());
        witAppoint.setDriverUserName(witPlan.getDriverUserName());
        witAppoint.setDriverUserPhone(driverUserPhone);
        witAppoint.setPlanId(witPlan.getPlanId());
        appointService.updateWitAppoint(witAppoint);
    }

    private WitBus getBus(Long routeId, WitPlan witPlan){
        int seatReservation = this.getSeatReservation();//车座位预留数
        List<WitBus> witBusList = busService.selectBusByPlanCount(routeId);
        for(WitBus witBus : witBusList){
            if(witPlan != null){
                Integer userCount = witPlan.getAppointCount();
                if(userCount < witBus.getFullLoad() - seatReservation){
                    return witBus;
                }
            }else{
                return witBus;
            }
        }
        return null;
    }

    /**
     * @Description 根据预约路线获取用户可执行的路线
     * @Author caiyanshan
     * @Date 2021/6/18 9:45
     * @Param [appoint]
     * @Return java.util.List<com.ruoyi.bus.domain.WitRoute>
     */
    private List<WitRoute> listRouteByUserAppoint(WitAppoint appoint){
        Long endSite = appoint.getEndSiteId();
        if(endSite == null){//没有则取路线终点站
            Long routeId = appoint.getRouteId();
            WitRoute witRoute = routeService.selectWitRouteById(routeId);
            List<WitRouteSite> witRouteSiteList = witRoute.getWitRouteSiteList();
            witRouteSiteList.sort((o1, o2) -> o2.getSort() - o1.getSort());
            WitRouteSite witRouteSite = witRouteSiteList.get(0);
            endSite = witRouteSite.getSiteId();
        }

        Long centerSite = appoint.getSiteId();
        //两个点确定可以行走的路线
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("endSite", endSite);
        paramMap.put("centerSite", centerSite);
        return routeService.selectRouteByTwoSideId(paramMap);//所有可用的路线ID
    }

    /**
     * 获取座位预留数
     * @return
     */
    private int getSeatReservation(){

        if(seatReservation == null){
            seatReservation = configService.selectConfigByKey("seat_reservation");
        }

        try{
            return Integer.parseInt(seatReservation);
        }catch (Exception e){
            return 5;//没配置就默认给与5个预留位
        }
    }

    private SysUser getDriverUser(Long userId){
        SysUser sysUser = userService.selectUserById(userId);
        if(sysUser != null){
            return sysUser;
        }
        return new SysUser();//可以不设置昵称,但不能报错,防止个人原因删除用户
    }

}
